package ui.graphical;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;

import logic.Logic;

import java.awt.Rectangle;
import java.awt.Toolkit;

import javax.swing.border.BevelBorder;
import javax.swing.JList;
import java.awt.Button;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SpinnerListModel;
import javax.swing.JPanel;

import domain.Korting;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;

public class Kortingen extends JFrame implements ActionListener, ListSelectionListener, ChangeListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7635246505772986284L;
	private Logic logic;
	private Button btnVerwijderen;
	private Button btnToevoegen;
	private JSpinner groepsGrootte;
	private JSpinner kortingsPercentage;
	private JPanel editKortingPanel;
	private JList listKortingen;
	
	private void vulListKortingen() {
		((DefaultListModel)listKortingen.getModel()).removeAllElements();
		List<Korting> kortingen = logic.getKortingen();
		for(Korting korting: kortingen) {
			((DefaultListModel)listKortingen.getModel()).addElement(korting);
		}
	}
	public Kortingen(Logic logic) {
		setIconImage(Toolkit.getDefaultToolkit().getImage(".\\images\\sm_kortingen.jpg"));
		setTitle("Groepskortingen");
		setBounds(new Rectangle(0, 0, 250, 265));
		setResizable(false);
		this.logic = logic;
		getContentPane().setLayout(null);
		
		listKortingen = new JList(new DefaultListModel());
		listKortingen.addListSelectionListener(this);
		listKortingen.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
		listKortingen.setBounds(10, 11, 137, 219);
		getContentPane().add(listKortingen);
		
		btnVerwijderen = new Button("Verwijderen");
		btnVerwijderen.addActionListener(this);
		btnVerwijderen.setBounds(155, 208, 80, 22);
		getContentPane().add(btnVerwijderen);
		
		btnToevoegen = new Button("Nieuw");
		btnToevoegen.addActionListener(this);
		btnToevoegen.setBounds(155, 180, 80, 22);
		getContentPane().add(btnToevoegen);
		
		editKortingPanel = new JPanel();
		editKortingPanel.setVisible(false);
		editKortingPanel.setBounds(150, 10, 93, 90);
		getContentPane().add(editKortingPanel);
		editKortingPanel.setLayout(null);
		
		JLabel lblGroepsgrootte = new JLabel("Groepsgrootte:");
		lblGroepsgrootte.setBounds(5, 5, 88, 14);
		editKortingPanel.add(lblGroepsgrootte);
		
		groepsGrootte = new JSpinner();
		groepsGrootte.addChangeListener(this);
		groepsGrootte.setBounds(5, 21, 70, 20);
		editKortingPanel.add(groepsGrootte);
		groepsGrootte.setModel(new SpinnerNumberModel(new Integer(2), new Integer(2), null, new Integer(1)));
		
		JLabel lblKortingsperc = new JLabel("Kortingsperc.:");
		lblKortingsperc.setBounds(5, 45, 88, 14);
		editKortingPanel.add(lblKortingsperc);
		
		kortingsPercentage = new JSpinner();
		kortingsPercentage.addChangeListener(this);
		kortingsPercentage.setBounds(5, 61, 70, 20);
		editKortingPanel.add(kortingsPercentage);
		kortingsPercentage.setModel(new SpinnerListModel(new String[] {"2.5", "5.0", "7.5", "10.0", "12.5", "15.0"}));
		vulListKortingen();
	}
	private void korting2Scherm(Korting korting) {
		if(korting==null) {
			editKortingPanel.setVisible(false);
		} else {
			groepsGrootte.setValue(korting.getMinDeelnemers());
			kortingsPercentage.setValue(korting.getKorting().toString());
			editKortingPanel.setVisible(true);
		}
	}
	private Korting getSelectedKorting() {
		Korting korting = null;
		if(listKortingen.getSelectedIndex()!=-1) {
			korting = (Korting)listKortingen.getModel().getElementAt(listKortingen.getSelectedIndex());
		}
		return korting;
	}
	private void updateListKortingen(Korting korting) {
		int idx = ((DefaultListModel)listKortingen.getModel()).indexOf(korting);
		((DefaultListModel)listKortingen.getModel()).setElementAt(korting, idx);
	}
	/**
	 * Korting toevoegen: het record met maxDeelnemers = 999 krijgt nu maxDeelnemers = minDeelnemers+1;
	 * het nieuwe record krijgt minDeelnemers = maxDeelnemers van eerstgenoemde record en maxDeelnemers = 999;
	 * bovendien krijgt het een korting van 2.5 + korting van eerstgenoemde record. Als er nog geen records
	 * zijn dan wordt alleen een nieuw record toegevoegd met minDeelnemers = 2, maxDeelnemers = 999 en
	 * korting = 2.5
	 */
	private void voegKortingToe() throws SQLException {
		Korting max = logic.getKortingByMaxDeelnemers(999);
		if(max!=null && max.getKorting().doubleValue()==15.0) {
			throw new SQLException("De maximale korting is al bereikt, kan geen korting meer toevoegen");
		}
		Korting nieuw = new Korting();
		if(max!=null) {
			max.setMaxDeelnemers(max.getMinDeelnemers()+1);
			nieuw.setKorting(BigDecimal.valueOf(max.getKorting().doubleValue() + 2.5));
			nieuw.setMinDeelnemers(max.getMaxDeelnemers());
			nieuw.setMaxDeelnemers(999);
			logic.saveKorting(max);
			logic.saveKorting(nieuw);
		} else {
			nieuw.setKorting(BigDecimal.valueOf(2.5));
			nieuw.setMinDeelnemers(2);
			nieuw.setMaxDeelnemers(999);
			logic.saveKorting(nieuw);
		}
		vulListKortingen();
		korting2Scherm(getSelectedKorting());
	}
	/**
	 * Verwijder korting: als er een record voor het te verwijderen record bestaat, wordt hiervan maxDeelnemers
	 * op minDeelnemers van het record na het te verwijderen record gezet, of als dat niet bestaat op 999; het
	 * record na het te verwijderen record hoeft niet te worden aangepast
	 * @throws SQLException
	 */
	private void verwijderKorting() throws SQLException {
		Korting korting = getSelectedKorting();
		if(korting!=null) {
			Korting voor = logic.getKortingByMaxDeelnemers(korting.getMinDeelnemers());
			Korting na = logic.getKortingByMinDeelnemers(korting.getMaxDeelnemers());
			if(voor!=null) {
				if(na!=null) {
					voor.setMaxDeelnemers(na.getMinDeelnemers());
				} else {
					voor.setMaxDeelnemers(999);
				}
				logic.saveKorting(voor);
			}
			logic.verwijderKorting(korting);
			vulListKortingen();
			korting2Scherm(getSelectedKorting());
		}
	}
	/**
	 * Verander groepsgrootte: als de grootte wordt verlaagd moet naar het record voor het te wijzigen
	 * record worden gekeken; de nieuwe grootte mag niet lager worden dan minDeelnemers + 1 van het record
	 * voor het te wijzigen record. Als de grootte wordt verhoogd wordt mag dit niet hoger worden dan
	 * maxDeelnemers-1 van het te wijzigen record.  Bovendien moet van het record voor het te wijzigen record
	 * (als het bestaat) de maxDeelnemers op de waarde van minDeelnemers van het te wijzigen record worden
	 * gezet.
	 * Als grootte niet wordt gewijzigd hoeven we niets te doen.
	 * @param korting
	 * @throws SQLException
	 */
	private void setGroepsGrootte(Korting korting, int groepsGrootte) throws SQLException {
		int huidig = korting.getMinDeelnemers();
		if(groepsGrootte<huidig) {
			Korting voor = logic.getKortingByMaxDeelnemers(korting.getMinDeelnemers());
			if(voor!=null) {
				if(groepsGrootte<voor.getMinDeelnemers()+1) {
					throw new SQLException("De nieuwe groepsgrootte mag niet kleiner zijn dan "+(voor.getMinDeelnemers()+1));
				}
				voor.setMaxDeelnemers(groepsGrootte);
				logic.saveKorting(voor);
				updateListKortingen(voor);
			}
			korting.setMinDeelnemers(groepsGrootte);
			logic.saveKorting(korting);
			updateListKortingen(korting);
		}
		else if(groepsGrootte>huidig) {
			if(groepsGrootte>korting.getMaxDeelnemers()-1) {
				throw new SQLException("De nieuwe groepsgrootte mag niet groter zijn dan "+(korting.getMaxDeelnemers()-1));
			}
			Korting voor = logic.getKortingByMaxDeelnemers(korting.getMinDeelnemers());
			korting.setMinDeelnemers(groepsGrootte);
			logic.saveKorting(korting);
			updateListKortingen(korting);
			if(voor!=null) {
				voor.setMaxDeelnemers(korting.getMinDeelnemers());
				logic.saveKorting(voor);
				updateListKortingen(voor);
			}
		}
	}
	/**
	 * Als percentage wordt gewijzigd wordt gekeken naar eventuele percentages van records voor en
	 * na het record waarvan de korting wordt gewijzigd. Het nieuwe kortingspercentage moet hier
	 * tussen liggen.
	 * @param korting
	 * @param percentage
	 * @throws SQLException
	 */
	private void setKortingsPercentage(Korting korting, double percentage) throws SQLException {
		Korting voor = logic.getKortingByMaxDeelnemers(korting.getMinDeelnemers());
		if(voor!=null && percentage <= voor.getKorting().doubleValue()) {
			korting2Scherm(korting);
			throw new SQLException("Kortingspercentage moet groter zijn dan "+voor.getKorting().toString()+"%");
		}
		Korting na = logic.getKortingByMinDeelnemers(korting.getMaxDeelnemers());
		if(na!=null && percentage >= na.getKorting().doubleValue()) {
			korting2Scherm(korting);
			throw new SQLException("Kortingspercentage moet kleiner zijn dan "+na.getKorting().toString()+"%");
		}
		korting.setKorting(BigDecimal.valueOf(percentage));
		logic.saveKorting(korting);
		updateListKortingen(korting);
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		try {
			if(e.getSource().equals(btnToevoegen)) {
				voegKortingToe();
			}
			else if(e.getSource().equals(btnVerwijderen)) {
				verwijderKorting();
			}
		} catch (SQLException ex) {
			UIHelper.errorMsg(ex.getMessage());
		}
	}
	public void valueChanged(ListSelectionEvent e) {
		if(!e.getValueIsAdjusting()) {
			Korting korting = getSelectedKorting();
			korting2Scherm(korting);
		}		
	}
	public void stateChanged(ChangeEvent e) {
		if(e.getSource().equals(groepsGrootte)) {
			try {
				setGroepsGrootte(getSelectedKorting(), (Integer) groepsGrootte.getValue());
			} catch (SQLException ex) {
				UIHelper.errorMsg(ex.getMessage());
			}
		}
		else if(e.getSource().equals(kortingsPercentage)) {
			try {
				setKortingsPercentage(getSelectedKorting(), Double.parseDouble((String) kortingsPercentage.getValue()));
			} catch (SQLException ex) {
				UIHelper.errorMsg(ex.getMessage());
			}
		}
	}
}
